#-*- coding: utf-8 -*-
import os
import sys
import socket
import signal
import fnmatch
import logging
import datetime
import subprocess
import pkg_resources
from time import sleep

from selenose.excepts import ToolError
from selenose.consts import GRID_CONFIG, LOGGER, WORK

# Get a logger
logger = logging.getLogger('%s.%s' % (LOGGER, __name__))

class Starter(object):
    '''Check file content to find a tag'''
    
    DELAY = 0.2
    
    def __init__(self, log):
        '''Initialize the starter'''
        # Store the log file descriptor
        self.log = log
        # Flush the log
        self.log.flush()
        # Get start position for log
        self.ilog = self.log.tell()
        
    def wait(self, tag, timeout):
        '''Wait till the tag or timeout'''
        # Get expiration delay
        expire = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
        # Loop to find
        while True:
            # Check if expired
            if datetime.datetime.now() >= expire:
                # Expired
                raise ToolError('failed to find %s in %s' % (tag, self.log.name))
            # Check if in log
            if self.find(self.log, tag, self.ilog): return
            # Else wait
            else: sleep(Starter.DELAY)

    def find(self, fd, tag, start):
        '''Try to find the tag in the file'''
        # Flush
        fd.flush()
        # Get the content of the file
        fil = open(fd.name, 'r')
        # Go to the start position
        fil.seek(start)
        # Read
        content = fil.read()
        # Close
        fil.close()
        # Check if found
        return content.find(tag) != -1

def get_last_version(folders, pattern, default=None):
    '''Get the last version of a jar given its folder and pattern'''
    # List the versions
    versions = {}
    # Go threw the folders
    for folder in folders:
        # Go threw the folder
        for fn in os.listdir(folder):
            # Check if match
            if fnmatch.fnmatch(fn, pattern):
                # If yes, add to list
                versions[fn] = os.path.join(folder, fn)
    # Check if at least one file
    if len(versions) == 0:
        # Not found
        if default is None: raise ToolError('%s not found' % pattern)
        # Else get the entry
        else: return pkg_resources.resource_filename(*default)
    # Found at least one. Sort!
    else:
        # Get the keys
        keys = versions.keys()
        # Sort versions
        keys.sort(reverse=True)
        # Return full path
        return versions[keys[0]]
    
def get_available_port():
    '''Get an available port'''
    # Create a socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
    # Bin on 0 to get next one
    sock.bind(('', 0))
    # Listen
    sock.listen(1)
    # Get the port
    port = sock.getsockname()[1]
    # Close the socket
    sock.close()
    # Return the port
    return port

def kill(process):
    '''Kill a process'''
    # Check if defined
    if process is None: logger.info('process not started')
    # Check if is finished
    elif process.poll() is not None: logger.info('process already finished with status %d' % process.poll())
    # Else stop it
    elif sys.platform == 'win32':
        # Get the specific windows package
        import win32api
        # Close process
        win32api.TerminateProcess(win32api.OpenProcess(1, 0, process.pid), 0)
    # Classical kill
    else: os.kill(process.pid, signal.SIGTERM)

def java(exe, classpath, cls, log, *args):
    '''Execute Java process'''
    # Get the base line
    jargs = [ exe, '-classpath', classpath, cls, ]
    # Add arguments
    jargs.extend(args)
    # Log
    logger.debug('execute: %s' % (' '.join(jargs)))
    # Start and return process
    return subprocess.Popen(jargs, stdout=log, stderr=subprocess.STDOUT)

def django_admin(order, settings, path, log, err, *args):
    '''Execute Django administration process'''
    # Get environ
    environ = os.environ.copy()
    # Set settings
    environ['DJANGO_SETTINGS_MODULE'] = settings
    # No buffer on output
    environ['PYTHONUNBUFFERED'] = 'true'
    # Check if on windows
    if sys.platform == 'win32':
        # Get the executable
        executable = os.path.abspath(sys.executable)
        # Create line
        dargs = [executable, os.path.join(os.path.dirname(executable), 'Scripts', 'django-admin.py'), ]
    # Only call this on UNIX
    else: dargs = ['django-admin.py', ]
    # Add other data
    dargs.extend([order, '--settings=%s' % settings, '--pythonpath=%s' % path, ])
    # Add arguments
    dargs.extend(args)
    # Check if error specified
    if err is None: err = subprocess.STDOUT
    # Log
    logger.debug('execute: %s' % (' '.join(dargs)))
    # Start and return the process
    return subprocess.Popen(dargs, env=environ, stdout=log, stderr=err, shell=False)

def create(folder):
    '''Create a folder'''
    # If not exists, create the folders
    if not os.path.exists(folder):
        # Create folder
        os.makedirs(folder)
        # Show that created
        return True
    # If exists and is a file, raise
    elif os.path.isfile(folder): raise ToolError('following path exists but is not a folder: %s' % folder)
    # Show that already exists
    return False

def geturlpath():
    '''Get the path where the URL of selenose server is stored'''
    # A file .selenose in user's HOME
    return os.path.join(os.getenv('USERPROFILE') or os.getenv('HOME'), '.selenose')

def geturl():
    '''Get the URL of the selenose server'''
    # Get the path
    path = geturlpath()
    # Check if exists
    if not os.path.isfile(path): return None
    # Get the file descriptor
    fd = open(path, 'r')
    # Read the content of the file
    url = fd.read()
    # Close the file descriptor
    fd.close()
    # Return the URL
    return url

def storeurl(url):
    '''Store the URL of selenose server'''
    # Get the file descriptor
    fd = open(geturlpath(), 'w')
    # Set the URL in the file
    fd.write(url)
    # Close the file descriptor
    fd.close()

def set_options(parser, binary=False):
    '''Add options to parser'''
    # Add grid configuration file
    parser.add_option('--grid',
                      action='store',
                      default = GRID_CONFIG,
                      dest='grid',
                      help='Grid configuration file (default: %s).' % GRID_CONFIG)
    # Add library folder
    parser.add_option('--lib',
                      action='append',
                      default=[],
                      dest='libs',
                      help='Java library folders. If not specified, extract needed libraries.')
    # Add Java executable
    parser.add_option('--java',
                      action='store',
                      default='java',
                      dest='java',
                      help='Java executable (default: java).')
    # Add settings file
    parser.add_option('--settings',
                      action='store',
                      default='settings',
                      dest='settings',
                      help='Django settings.')
    # Work folder
    parser.add_option('--work',
                      action='store',
                      default=WORK,
                      dest='work',
                      help='Selenose work folder (default: %s).' % WORK)
    # No server
    parser.add_option('--keep',
                      action='store_true',
                      default=False,
                      dest='keep',
                      help='Keep logs in work folder after tests.')
    # Check if start server
    if not binary:
        # No server
        parser.add_option('--no-servers',
                          action='store_true',
                          default=False,
                          dest='dev',
                          help='Do not start servers if already started with `selenose` binary.')

def gettell(path):
    '''Get the last position in the file'''
    # Check if exists
    if not os.path.isfile(path):
        # Raise an error
        raise ToolError("file doesn't exist: %s" % path)
    # Get the file descriptor
    fd = open(path, 'r')
    # Go to the end of the file
    fd.seek(0, 2)
    # Get the position
    tell = fd.tell()
    # Close the file descriptor
    fd.close()
    # Return the position
    return tell

def getcontent(path, start=0):
    '''Get the content of the file located at the provided path'''
    # Check if exists
    if not os.path.isfile(path):
        # Raise an error
        raise ToolError("file doesn't exist: %s" % path)
    # Get the file descriptor
    fd = open(path, 'r')
    # Go to the position
    fd.seek(start)
    # Get the content
    content = fd.read()
    # Close the file descriptor
    fd.close()
    # Return the content
    return content

def is_26_plus():
    '''Check if PYTHON version is 2.6 plus'''
    # Check versions
    return ( sys.version_info[0] > 2 ) or ( sys.version_info[0] == 2 and sys.version_info[1] >= 6 )
    
